package com.eian.boot.common.core.exception.core;

import com.eian.boot.common.core.exception.BusinessException;
import com.eian.boot.common.core.model.CommonResult;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingPathVariableException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.NoHandlerFoundException;

import java.util.Objects;

/**
 * 全局异常处理器
 *
 * @author alex.meng
 */
@Slf4j
@Order(80)
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 业务异常
     */
    @ExceptionHandler({BusinessException.class})
    public CommonResult<Void> handleBusinessException(BusinessException e, HttpServletRequest request) {
        String requestUri = request.getRequestURI();
        log.error("请求API '{}',业务异常信息：{}", requestUri, e.getMessage(), e);

        Integer code = e.getCode();
        return Objects.nonNull(code) ? CommonResult.fail(code, e.getMessage()) : CommonResult.fail(e.getMessage());
    }

    /**
     * 请求方式不支持
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public CommonResult<Void> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e,
                                                                  HttpServletRequest request) {
        String requestUri = request.getRequestURI();
        log.error("请求API '{}',不支持'{}'请求", requestUri, e.getMethod());
        return CommonResult.fail(e.getMessage());
    }

    /**
     * 请求路径中缺少必需的路径变量
     */
    @ExceptionHandler(MissingPathVariableException.class)
    public CommonResult<Void> handleMissingPathVariableException(MissingPathVariableException e, HttpServletRequest request) {
        String requestUri = request.getRequestURI();
        log.error("请求路径中缺少必需的路径变量，请检查请求地址'{}'是否正确", requestUri);
        return CommonResult.fail(String.format("请求路径中缺少必需的路径变量：%s", e.getVariableName()));
    }

    /**
     * 请求参数缺失
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public CommonResult<Void> handleMissingServletRequestParameterException(MissingServletRequestParameterException e, HttpServletRequest request) {
        String requestUri = request.getRequestURI();
        log.error("请求参数缺失，请检查请求地址'{}'是否正确", requestUri);
        return CommonResult.fail(String.format("请求参数缺失：%s", e.getParameterName()));
    }

    /**
     * 参数类型不匹配
     */
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public CommonResult<Void> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e, HttpServletRequest request) {
        String requestUri = request.getRequestURI();
        log.error("参数类型不匹配，请检查请求地址'{}'是否正确", requestUri);
        return CommonResult.fail(String.format("参数类型不匹配，参数%s的值'%s'不能转换为%s类型",
                e.getName(), e.getValue(), Objects.requireNonNull(e.getRequiredType()).getSimpleName()));
    }

    /**
     * 参数校验异常
     * 返回 HTTP 400 Bad Request
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<CommonResult<Void>> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        log.warn("参数校验异常:{}", e.getMessage());
        String message = Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage();
        CommonResult<Void> result = CommonResult.fail(HttpStatus.BAD_REQUEST.value(), message);
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(result);
    }

    /**
     * 参数绑定异常
     * 返回 HTTP 400 Bad Request
     */
    @ExceptionHandler(BindException.class)
    public ResponseEntity<CommonResult<Void>> handleBindException(BindException e) {
        log.warn("参数绑定异常:{}", e.getMessage());
        String message = Objects.requireNonNull(e.getFieldError()).getDefaultMessage();
        CommonResult<Void> result = CommonResult.fail(HttpStatus.BAD_REQUEST.value(), message);
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(result);
    }

    /**
     * 请求地址不存在
     * 返回 HTTP 404 Not Found
     */
    @ExceptionHandler(NoHandlerFoundException.class)
    public ResponseEntity<CommonResult<Void>> handleNoHandlerFoundException(NoHandlerFoundException e, HttpServletRequest request) {
        String requestUri = request.getRequestURI();
        log.error("请求API '{}'不存在", requestUri);
        CommonResult<Void> result = CommonResult.fail(HttpStatus.NOT_FOUND.value(), "请求地址不存在");
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(result);
    }

    /**
     * 拦截未知的运行时异常
     */
    @ExceptionHandler(RuntimeException.class)
    public CommonResult<Void> handleRuntimeException(RuntimeException e, HttpServletRequest request) {
        String requestUri = request.getRequestURI();
        log.error("请求API '{}',发生未知异常.", requestUri, e);
        return CommonResult.fail(CommonResult.FAIL, "系统发生异常，请联系管理员");
    }

    /**
     * 系统异常
     */
    @ExceptionHandler(Exception.class)
    public CommonResult<Void> handleException(Exception e, HttpServletRequest request) {
        String requestUri = request.getRequestURI();
        log.error("请求API '{}',发生系统异常.", requestUri, e);
        return CommonResult.fail(CommonResult.FAIL, "系统发生异常，请联系管理员");
    }
}

